﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;

namespace RoiControllers
{
    public class URectangle2 : ShapeBase
    {
        #region 字段|属性
        #region 字段
        private PointF rotationCenter;          //旋转中心
        private int rotateHandleSize = 15;      //选择手柄大小
        #endregion
        #region 属性
        public float X { get => Region.X; set => _rectangleF.X = value; }
        public float Y { get => Region.Y; set => _rectangleF.Y = value; }
        public PointF Point { get => new PointF(X, Y); set => _rectangleF.Location = value; }
        public float Width { get => Region.Width; set => _rectangleF.Width = value; }
        public float Height { get => Region.Height; set => _rectangleF.Height = value; }
        public float RotationAngle
        {
            get => _angle;
            set
            {
                _angle = value;
            }
        }
        #endregion
        #endregion

        #region 构造函数
        public URectangle2() : base()
        {
            Type = ShapeType.Rectangle2;
            Region = new RectangleF(0, 0, 100, 100);
            RotationAngle = 0F;
        }
        public URectangle2(float x, float y, float width, float height, float angle) : base()
        {
            Type = ShapeType.Rectangle2;
            Region = new RectangleF(x, y, width, height);
            RotationAngle = angle;
        }
        public URectangle2(PointF location, SizeF sizeF, float angle) : base()
        {
            Type = ShapeType.Rectangle2;
            Region = new RectangleF(location, sizeF);
            RotationAngle = angle;
        }
        #endregion

        #region 基础绘制相关方法
        private void DrawRegionCenter(Graphics graphics)
        {
            RectangleF rectangle = Region;
            // 1、计算矩形中心坐标
            float centerX = rectangle.X + rectangle.Width / 2;
            float centerY = rectangle.Y + rectangle.Height / 2;
            // 2、线长度大小（根据矩形大小自适应）
            float lineHalfLength = 3;
            // 3、绘制箭头
            using (Pen arrowPen = new Pen(BackColor, BorderWidth))
            {
                // 3.1 水平线
                PointF left = new PointF(centerX - lineHalfLength, centerY);
                PointF right = new PointF(centerX + lineHalfLength, centerY);
                graphics.DrawLine(arrowPen, left, right);
                // 3.2 垂直线
                PointF top = new PointF(centerX, centerY - lineHalfLength);
                PointF bottom = new PointF(centerX, centerY + lineHalfLength);
                graphics.DrawLine(arrowPen, top, bottom);
            }
        }
        /// <summary> 绘制形状描述文本 </summary>
        private void DrawDescription(Graphics graphics)
        {
            RectangleF rectangle = Region;
            using (SolidBrush brush = new SolidBrush(Color.LightGreen))
            {
                Font descriptionFont = new Font("Arial", 9);
                string text = $"{Description}  ，位置{X},{Y} 角度：{RotationAngle:F3}";
                SizeF maxTextSize = graphics.MeasureString(text, descriptionFont);
                float x = X + Width / 2 - maxTextSize.Width / 2;
                float y = Y + Height / 2 - maxTextSize.Height;
                graphics.DrawString(text, descriptionFont, brush, x, y);
            }
        }
        /// <summary>绘制所有形状手柄 </summary>
        private void DrawHandles(Graphics graphics)
        {
            RectangleF rectangle = Region;
            // 四个角的手柄
            DrawHandle(graphics, rectangle.Left, rectangle.Top);       // 左上角
            DrawHandle(graphics, rectangle.Right, rectangle.Top);      // 右上角
            DrawHandle(graphics, rectangle.Left, rectangle.Bottom);    // 左下角
            DrawHandle(graphics, rectangle.Right, rectangle.Bottom);   // 右下角
            // 计算中点位置   
            float midX = rectangle.Left + rectangle.Width / 2;
            float midY = rectangle.Top + rectangle.Height / 2;
            // 四个边中点的手柄：左右上下
            DrawHandle(graphics, midX, rectangle.Top);          // 上边中点
            DrawHandle(graphics, midX, rectangle.Bottom);       // 下边中点

        }
        /// <summary> 在左右边框中间位置绘制垂直方向箭头（↓↓）  </summary>
        private void DrawVerticalDirectionArrows(Graphics graphics)
        {
            RectangleF rectangle = Region;
            // 1、计算左右边框的中间X坐标
            float leftMidX = rectangle.Left;
            float rightMidX = rectangle.Right;
            float verticalCenterY = rectangle.Top + rectangle.Height / 2;
            // 2、箭头大小（根据矩形大小自适应）
            float arrowSize = Math.Min(10, rectangle.Height / 4);
            float arrowHalfSize = arrowSize / 2;
            // 3、绘制箭头
            using (Pen arrowPen = new Pen(BackColor, BorderWidth + 1))
            {
                // 3.1 左侧向下箭头（垂直方向）
                PointF leftArrowCenter = new PointF(leftMidX, verticalCenterY + arrowSize);
                PointF leftArrowRight = new PointF(leftMidX + arrowHalfSize, verticalCenterY + arrowSize / 2);
                PointF leftArrowLeft = new PointF(leftMidX - arrowHalfSize, verticalCenterY + arrowHalfSize);
                graphics.DrawLine(arrowPen, leftArrowRight, leftArrowCenter);
                graphics.DrawLine(arrowPen, leftArrowLeft, leftArrowCenter);
                // 3.2 右侧向下箭头（垂直方向）
                PointF rightArrowCenter = new PointF(rightMidX, verticalCenterY + arrowSize);
                PointF rightArrowLeft = new PointF(rightMidX - arrowHalfSize, verticalCenterY + arrowHalfSize);
                PointF rightArrowRight = new PointF(rightMidX + arrowHalfSize, verticalCenterY + arrowHalfSize);
                graphics.DrawLine(arrowPen, rightArrowLeft, rightArrowCenter);
                graphics.DrawLine(arrowPen, rightArrowRight, rightArrowCenter);
            }
        }
        /// <summary> 绘制矩形边缘 </summary>
        private void DrawBorder(Graphics graphics)
        {
            // 绘制矩形
            using (Pen pen = new Pen(BackColor, BorderWidth))
            {
                graphics.DrawRectangle(pen, Rectangle.Round(Region));
            }
        }
        /// <summary> 填充矩形区域 </summary>
        private void DrawRegion(Graphics graphics)
        {
            // 填充矩形
            using (SolidBrush brush = new SolidBrush(Color.FromArgb(Alpha, BackColor)))
            {
                graphics.FillRectangle(brush, Region);
            }
        }
        /// <summary> 绘制旋转圆弧手柄 </summary>
        private void DrawRotateHandle(Graphics graphics)
        {
            // 4、绘制圆弧
            using (Pen arcPen = new Pen(HandleColor, 1))
            {
                graphics.DrawArc(arcPen, this.Region.Right - 3, this.Region.Top - 10,
                    rotateHandleSize, rotateHandleSize, 245, 135);
            }
        }
        /// <summary> 启用变换绘制的方法 </summary>
        private void UseTransformDraw(Action<Graphics> method, Graphics graphics)
        {
            RectangleF rectangle = Region;
            // 1、保存原始变换状态
            GraphicsState state = graphics.Save();
            // 2、设置旋转中心（矩形中心）
            rotationCenter = new PointF(rectangle.X + rectangle.Width / 2f, rectangle.Y + rectangle.Height / 2f);
            // 3、应用旋转变换
            graphics.TranslateTransform(rotationCenter.X, rotationCenter.Y);
            graphics.RotateTransform(RotationAngle);
            graphics.TranslateTransform(-rotationCenter.X, -rotationCenter.Y);
            // 4、**执行方法**
            method.Invoke(graphics);
            // 5、恢复原始变换状态
            graphics.Restore(state);
        }
        #endregion

        #region 旋转绘制相关
        /// <summary> 是否在旋转矩形 </summary>
        private bool IsInRotatedRectangle(PointF point)
        {
            RectangleF rect = this.Region;
            PointF center = new PointF(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f);
            // 将检测点反向旋转
            PointF unrotatedPoint = RotatePoint(point, center, RotationAngle);
            return rect.Contains((int)unrotatedPoint.X, (int)unrotatedPoint.Y);
        }
        #endregion

        #region 方法重写：绘制形状相关
        public override void Rotate(PointF point)
        {
            if (!IsRotating) return;
            //// 1、计算旋转中心（矩形中心）
            //PointF center = new PointF(Region.X + Region.Width / 2, Region.Y + Region.Height / 2);
            //PointF prevVector = new PointF(LastLocation.X - center.X, LastLocation.Y - center.Y);
            //PointF currentVector = new PointF(point.X - center.X, point.Y - center.Y);
            ////计算角度
            //float angle = (float)(Math.Atan2(currentVector.Y, currentVector.X) - (float)(Math.Atan2(prevVector.Y, prevVector.X)));
            //angle = angle * (180f / (float)Math.PI);
            //RotationAngle += angle;
            //RotationAngle %= 360;
            //LastLocation = point;

            // 1、计算旋转中心（矩形中心）
            PointF rotateCenter = new PointF(X + Width / 2f, Y + Height / 2f);
            // 2、计算当前鼠标位置相对于中心点的向量
            PointF currentVector = new PointF(point.X - rotateCenter.X, point.Y - rotateCenter.Y);
            // 3、计算上次鼠标位置相对于中心点的向量
            PointF lastVector = new PointF(LastLocation.X - rotateCenter.X, LastLocation.Y - rotateCenter.Y);
            // 4、计算叉积（z分量）来确定旋转方向
            float crossProduct = lastVector.X * currentVector.Y - lastVector.Y * currentVector.X;
            // 5、计算点积和向量长度来计算角度变化
            float dotProduct = lastVector.X * currentVector.X + lastVector.Y * currentVector.Y;
            float lastLength = (float)Math.Sqrt(lastVector.X * lastVector.X + lastVector.Y * lastVector.Y);
            float currentLength = (float)Math.Sqrt(currentVector.X * currentVector.X + currentVector.Y * currentVector.Y);
            // 6、数值判断计算
            // 避免除以零
            if (lastLength > 0 && currentLength > 0)
            {
                float cosAngle = dotProduct / (lastLength * currentLength);
                // 确保cosAngle在有效范围内[-1,1]，避免浮点误差
                cosAngle = Math.Max(-1, Math.Min(1, cosAngle));
                float angleDelta = (float)(Math.Acos(cosAngle) * (180.0 / Math.PI));
                // 根据叉积符号确定旋转方向
                // 逆时针旋转
                if (crossProduct > 0) RotationAngle += angleDelta;
                // 顺时针旋转
                else if (crossProduct < 0) RotationAngle -= angleDelta;
                // 限制角度在0-360度之间
                RotationAngle = RotationAngle % 360;
                if (RotationAngle < 0) RotationAngle += 360;
            }
            LastLocation = point;
            ExecuteRotateCallback();
        }
        public override void Move(PointF point)
        {
            X += point.X;
            Y += point.Y;
            LastLocation = point;
            ExecuteMoveCallback();
        }
        public override void Resize(PointF point)
        {
            RectangleF rect = Region;
            switch (HandleType)
            {
                // 四条边中点的手柄
                case ShapeHandleType.Top:       // 上边中点：调整高度（Y方向）
                    rect.Y += point.Y;
                    rect.Height = rect.Height - point.Y;
                    break;
                case ShapeHandleType.Bottom:    // 下边中点：调整高度（Y方向）
                    rect.Height += point.Y;
                    break;
                case ShapeHandleType.Left:     // 左边中点：调整宽度（X方向）
                    rect.X += point.X;
                    rect.Width -= point.X;
                    break;
                case ShapeHandleType.Right:    // 右边中点：调整宽度（X方向）
                    rect.Width += point.X;
                    break;
                // 四条边角点的手柄
                case ShapeHandleType.TopLeft:   //左上角
                    rect.X += point.X;
                    rect.Y += point.Y;
                    rect.Width -= point.X;
                    rect.Height -= point.Y;
                    break;
                case ShapeHandleType.TopRight:  //右上角
                    rect.Y += point.Y;
                    rect.Width += point.X;
                    rect.Height -= point.Y;
                    break;
                case ShapeHandleType.BottomLeft:    //左下角
                    rect.X += point.X;
                    rect.Width -= point.X;
                    rect.Height += point.Y;
                    break;
                case ShapeHandleType.BottomRight:   //右下角：调整宽高
                    rect.Width += point.X;
                    rect.Height += point.Y;
                    break;
            }
            if (rect.Width > 10 && rect.Height > 10) Region = rect;
            ExecuteResizeCallback();
        }
        public override void DrawShapeWithHandle(Graphics graphics)
        {
            //不感兴趣直接绘制
            if (!IsInterest)
            {
                //保留原来颜色
                Color tempBackColor = BackColor;
                BackColor = InterestColor;
                // 1.1、绘制（填充）背景区域
                UseTransformDraw(DrawRegion, graphics);
                // 1.2、绘制水平方向箭头
                UseTransformDraw(DrawVerticalDirectionArrows, graphics);
                // 1.3、绘制旋转手柄(圆弧)
                UseTransformDraw(DrawRotateHandle, graphics);
                // 1.4、绘制形状手柄
                DrawHandles(graphics);
                // 2、绘制边缘
                UseTransformDraw(DrawBorder, graphics);
                // 3、绘制区域中心
                UseTransformDraw(DrawRegionCenter, graphics);
                // 4、绘制形状描述
                UseTransformDraw(DrawDescription, graphics);
                // 恢复颜色
                BackColor = tempBackColor;
                return;
            }
            //感兴趣根据是否选中绘制
            if (IsSelected)
            {
                // 1.1、绘制（填充）背景区域
                UseTransformDraw(DrawRegion, graphics);
                // 1.2、绘制水平方向箭头
                UseTransformDraw(DrawVerticalDirectionArrows, graphics);
                // 1.3、绘制旋转手柄(圆弧)
                UseTransformDraw(DrawRotateHandle, graphics);
                // 1.4、绘制形状手柄
                DrawHandles(graphics);
            }
            // 2、绘制边缘
            UseTransformDraw(DrawBorder, graphics);
            // 3、绘制区域中心
            UseTransformDraw(DrawRegionCenter, graphics);
            // 4、绘制形状描述
            UseTransformDraw(DrawDescription, graphics);
        }
        public override void DrawHandle(Graphics graphics, float x, float y)
        {
            RectangleF rectangle = Region;
            // 1、保存原始变换状态
            GraphicsState state = graphics.Save();
            // 2、设置旋转中心（矩形中心）
            rotationCenter = new PointF(rectangle.X + rectangle.Width / 2f, rectangle.Y + rectangle.Height / 2f);
            // 3、应用旋转变换
            graphics.TranslateTransform(rotationCenter.X, rotationCenter.Y);
            graphics.RotateTransform(RotationAngle);
            graphics.TranslateTransform(-rotationCenter.X, -rotationCenter.Y);
            // 4、创建矩形
            Rectangle handleRect = new Rectangle((int)x - HandleSize / 2, (int)y - HandleSize / 2, HandleSize, HandleSize);
            // 5、绘制与填充
            using (Pen pen = new Pen(HandleColor))
            {
                graphics.DrawRectangle(pen, handleRect);
            }
            using (SolidBrush brush = new SolidBrush(Color.FromArgb(Alpha * 2, HandleColor)))
            {
                graphics.FillRectangle(brush, handleRect);
            }
            // 5、恢复原始变换状态
            graphics.Restore(state);
        }
        public override void DrawHandle(Graphics graphics, PointF point) { }
        public override ShapeHandleType GetHandleType(PointF point)
        {
            RectangleF rectTemp = this.Region;
            // 1、计算矩形中心
            PointF center = new PointF(rectTemp.X + rectTemp.Width / 2f, rectTemp.Y + rectTemp.Height / 2f);
            // 2、旋转手柄的原始位置（未旋转时）
            PointF rotateHandleCenter = new PointF(rectTemp.Right - 3 + rotateHandleSize / 2f, rectTemp.Top - 10 + rotateHandleSize / 2f);
            // 3、应用旋转后的实际位置
            PointF rotatedHandleCenter = RotatePoint(rotateHandleCenter, center, RotationAngle);
            // 4、检测点是否在旋转后的手柄区域内
            RectangleF rect = new RectangleF(rectTemp.X, rectTemp.Y, rectTemp.Width, rectTemp.Height);
            // 计算中点坐标
            int midX = (int)(rect.Left + rect.Width / 2);
            int midY = (int)(rect.Top + rect.Height / 2);
            //旋转
            if (IsInRotateHandle(point))
                return ShapeHandleType.Rotation;
            // 四个角的手柄
            if (IsInHandle(point, new Point((int)rect.Left, (int)rect.Top)))
                return ShapeHandleType.TopLeft;
            if (IsInHandle(point, new Point((int)rect.Right, (int)rect.Top)))
                return ShapeHandleType.TopRight;
            if (IsInHandle(point, new Point((int)rect.Left, (int)rect.Bottom)))
                return ShapeHandleType.BottomLeft;
            if (IsInHandle(point, new Point((int)rect.Right, (int)rect.Bottom)))
                return ShapeHandleType.BottomRight;
            // 四个边中点的手柄
            if (IsInHandle(point, new Point(midX, (int)rect.Top)))
                return ShapeHandleType.Top;
            if (IsInHandle(point, new Point((int)rect.Right, midY)))
                return ShapeHandleType.Right;
            if (IsInHandle(point, new Point(midX, (int)rect.Bottom)))
                return ShapeHandleType.Bottom;
            if (IsInHandle(point, new Point((int)rect.Left, midY)))
                return ShapeHandleType.Left;
            return ShapeHandleType.None;
        }
        public override Cursor GetSystemHandleType(PointF point)
        {
            ShapeHandleType handleType = GetHandleType(point);
            // 旋转手柄返回手型光标
            if (handleType == ShapeHandleType.Rotation) return Cursors.Hand;
            // 如果不在任何手柄上，返回默认光标
            if (handleType == ShapeHandleType.None) return Cursors.SizeAll;
            // 计算旋转后的角度（0°~360°）
            float angle = RotationAngle % 360;
            if (angle < 0) angle += 360;
            // 根据旋转角度调整光标方向
            switch (handleType)
            {
                // 四个角点的手柄
                case ShapeHandleType.TopLeft:
                case ShapeHandleType.BottomRight:
                    // 默认是 SizeNWSE（左上↖右下↘）4
                    if (angle >= 25 && angle < 70) return Cursors.SizeNS;
                    if (angle >= 70 && angle < 115) return Cursors.SizeNESW;
                    if (angle >= 115 && angle < 160) return Cursors.SizeWE;
                    if (angle >= 160 && angle < 205) return Cursors.SizeNWSE;
                    if (angle >= 205 && angle < 250) return Cursors.SizeNS;
                    if (angle >= 250 && angle < 295) return Cursors.SizeNS;
                    if (angle >= 295 && angle < 340) return Cursors.SizeWE;
                    if (angle >= 340 && angle < 25) return Cursors.SizeNESW;
                    return Cursors.SizeNWSE;

                case ShapeHandleType.TopRight:
                case ShapeHandleType.BottomLeft:
                    // 默认是 SizeNESW（右上↗左下↙）
                    if (angle >= 25 && angle < 70) return Cursors.SizeWE;
                    if (angle >= 70 && angle < 115) return Cursors.SizeNWSE;
                    if (angle >= 115 && angle < 160) return Cursors.SizeNS;
                    if (angle >= 160 && angle < 205) return Cursors.SizeNESW;
                    if (angle >= 205 && angle < 250) return Cursors.SizeWE;
                    if (angle >= 250 && angle < 295) return Cursors.SizeNWSE;
                    if (angle >= 295 && angle < 340) return Cursors.SizeNS;
                    if (angle >= 340 && angle < 25) return Cursors.SizeNESW;
                    return Cursors.SizeNESW;

                // 四个边中点的手柄
                case ShapeHandleType.Top:
                case ShapeHandleType.Bottom:
                    // 默认是 SizeNESW（右上↗左下↙）
                    if (angle >= 25 && angle < 70) return Cursors.SizeNESW;
                    if (angle >= 70 && angle < 115) return Cursors.SizeWE;
                    if (angle >= 115 && angle < 160) return Cursors.SizeNWSE;
                    if (angle >= 160 && angle < 205) return Cursors.SizeNS;
                    if (angle >= 205 && angle < 250) return Cursors.SizeNESW;
                    if (angle >= 250 && angle < 295) return Cursors.SizeWE;
                    if (angle >= 295 && angle < 340) return Cursors.SizeNWSE;
                    if (angle >= 340 && angle < 25) return Cursors.SizeNESW;
                    return Cursors.SizeNS;

                case ShapeHandleType.Left:
                case ShapeHandleType.Right:
                    // 默认是 SizeNESW（右上↗左下↙）
                    if (angle >= 25 && angle < 70) return Cursors.SizeNWSE;
                    if (angle >= 70 && angle < 115) return Cursors.SizeNS;
                    if (angle >= 115 && angle < 160) return Cursors.SizeNESW;
                    if (angle >= 160 && angle < 205) return Cursors.SizeWE;
                    if (angle >= 205 && angle < 250) return Cursors.SizeNWSE;
                    if (angle >= 250 && angle < 295) return Cursors.SizeNS;
                    if (angle >= 295 && angle < 340) return Cursors.SizeNESW;
                    if (angle >= 340 && angle < 25) return Cursors.SizeNESW;
                    return Cursors.SizeWE;
                default:
                    return Cursors.SizeAll;
            }
        }
        public override bool IsInRegion(PointF point)
        {
            // 先检测手柄
            if (GetHandleType(point) != ShapeHandleType.None)
                return true;
            // 检测旋转区域
            if (IsInRotateHandle(point))
                return true;
            // 检测是否在旋转后的矩形内
            return IsInRotatedRectangle(point);
        }
        public override bool IsInBackground(PointF point)
        {
            return IsInRotatedRectangle(point) && GetHandleType(point) == ShapeHandleType.None;
        }
        public override bool IsInHandle(PointF inPoint, PointF point)
        {
            // 1、创建手柄矩形，计算旋转中心。
            int detectionSize = HandleOutSize + 5;
            RectangleF rectangle = new RectangleF(
                point.X - detectionSize / 2f,
                point.Y - detectionSize / 2f,
                detectionSize, detectionSize);
            // 2、计算矩形中心点
            PointF center = new PointF(X + Width / 2f, Y + Height / 2f);
            // 3、将检测点反向旋转回矩形未旋转时的坐标系
            PointF unrotatedPoint = RotatePoint(inPoint, center, -RotationAngle);
            // 4、检查反向旋转后的点是否在原始矩形内
            return rectangle.Contains(unrotatedPoint);
        }
        public override bool IsInRotateHandle(PointF point)
        {
            RectangleF rect = Region;
            // 1、计算矩形中心
            PointF center = new PointF(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f);
            // 2、旋转手柄的原始位置（旋转前）
            PointF rotateHandleCenter = new PointF(rect.Right - 3 + rotateHandleSize / 2f, rect.Top - 10 + rotateHandleSize / 2f);
            // 3、应用旋转后的实际位置（旋转后）
            PointF rotatedHandleCenter = RotatePoint(rotateHandleCenter, center, RotationAngle);
            // 4、检测点是否在旋转后的手柄区域内
            RectangleF rotateHandleRect = new RectangleF(
                rotatedHandleCenter.X - rotateHandleSize / 2f,
                rotatedHandleCenter.Y - rotateHandleSize / 2f,
                rotateHandleSize, rotateHandleSize);
            return rotateHandleRect.Contains(point);
        }
        #endregion

        #region 重写委托回调方法
        public override void ExecuteMoveCallback()
        {
            MoveEvents?.Invoke(this, Region.Location);
        }
        public override void ExecuteRotateCallback()
        {
            RotateEvents?.Invoke(this, Point);
        }
        public override void ExecuteResizeCallback()
        {
            ResizeEvents?.Invoke(this, Point);
        }
        public override void ExecuteAttachCallback()
        {
            AttachEvents?.Invoke(this, Point);
        }
        public override void ExecuteDetachCallback()
        {
            DetachEvents?.Invoke(this, Point);
        }
        public override void ExecuteSelectedCallback()
        {
            SelectedEvents?.Invoke(this, Point);
        }
        #endregion
    }
}
